# -*- coding: utf-8 -*-
# @Time    : 2024/7/15 15:56
# @Author  : yujiahao
# @File    : 27_fastapi_dependency_ch.py
# @description:子依赖项
from typing import Union

from fastapi import FastAPI, Depends, Cookie

'''
FastAPI 支持创建含子依赖项的依赖项。

并且，可以按需声明任意深度的子依赖项嵌套层级。

FastAPI 负责处理解析不同深度的子依赖项。

'''

app = FastAPI()


# 第一层依赖
def query_extractor(q: str | None = None):
    return q


# 第二层依赖项

# 同时用该依赖项自身再声明一个依赖项（所以这也是一个「依赖项」）
def query_or_cookie_extractor(
        q: str = Depends(query_extractor),
        last_query: Union[str, None] = Cookie(default=None),
):
    '''
    - 尽管该函数自身是依赖项，但还声明了另一个依赖项（它「依赖」于其他对象）
        - 该函数依赖 query_extractor, 并把 query_extractor 的返回值赋给参数 q
    - 同时，该函数还声明了类型是 str 的可选 cookie（last_query）
        - 用户未提供查询参数 q 时，则使用上次使用后保存在 cookie 中的查询
    '''
    if not q:
        return last_query
    return q


# 使用依赖项，没啥花里胡哨的，依赖注入无非是与路径操作函数一样的函数罢了（有安全保证和节省代码量，后面会在安全这里再说）
@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
    '''
    【多次使用同一个依赖项】
    如果在同一个路径操作 多次声明了同一个依赖项，例如，多个依赖项共用一个子依赖项，FastAPI 在处理同一请求时，只调用一次该子依赖项。

    FastAPI 不会为同一个请求多次调用同一个依赖项，而是把依赖项的返回值进行「缓存」，并把它传递给同一请求中所有需要使用该返回值的「依赖项」。

    在高级使用场景中，如果不想使用「缓存」值，而是为需要在同一请求的每一步操作（多次）中都实际调用依赖项，可以把 Depends 的参数 use_cache 的值设置为 False
    '''
    return {"q_or_cookie": query_or_default}
